var dianduanyuan_x = 0;
var dianduanyuan_y = 0;
var dianduanyuan_z = 4;
var rotation = 60;
var rotation_pos_x = 1;
var rotation_pos_y = 1;
var rotation_pos_z = 1;

var shinness = 300;

var indicesArray = [
  0,
  1,
  2,
  0,
  2,
  3, // front
  4,
  5,
  6,
  4,
  6,
  7, // right
  8,
  9,
  10,
  8,
  10,
  11, // up
  12,
  13,
  14,
  12,
  14,
  15, // left
  16,
  17,
  18,
  16,
  18,
  19, // down
  20,
  21,
  22,
  20,
  22,
  23, // back
];

var normalsArray = [
  0.0,
  0.0,
  1.0,
  0.0,
  0.0,
  1.0,
  0.0,
  0.0,
  1.0,
  0.0,
  0.0,
  1.0, // v0-v1-v2-v3 front
  1.0,
  0.0,
  0.0,
  1.0,
  0.0,
  0.0,
  1.0,
  0.0,
  0.0,
  1.0,
  0.0,
  0.0, // v0-v3-v4-v5 right
  0.0,
  1.0,
  0.0,
  0.0,
  1.0,
  0.0,
  0.0,
  1.0,
  0.0,
  0.0,
  1.0,
  0.0, // v0-v5-v6-v1 up
  -1.0,
  0.0,
  0.0,
  -1.0,
  0.0,
  0.0,
  -1.0,
  0.0,
  0.0,
  -1.0,
  0.0,
  0.0, // v1-v6-v7-v2 left
  0.0,
  -1.0,
  0.0,
  0.0,
  -1.0,
  0.0,
  0.0,
  -1.0,
  0.0,
  0.0,
  -1.0,
  0.0, // v7-v4-v3-v2 down
  0.0,
  0.0,
  -1.0,
  0.0,
  0.0,
  -1.0,
  0.0,
  0.0,
  -1.0,
  0.0,
  0.0,
  -1.0, // v4-v7-v6-v5 back
];

var colorsArray = [
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, // v0-v1-v2-v3 front
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, // v0-v3-v4-v5 right
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, // v0-v5-v6-v1 up
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, // v1-v6-v7-v2 left
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, // v7-v4-v3-v2 down
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, // v4-v7-v6-v5 back

  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, // v0-v1-v2-v3 front
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, // v0-v3-v4-v5 right
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, // v0-v5-v6-v1 up
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, // v1-v6-v7-v2 left
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, // v7-v4-v3-v2 down
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1,
  1, // v4-v7-v6-v5 back
];

function GetVerticesArray() {
  var verticesArray = [
    0.5,
    0.5,
    0.5,
    -0.5,
    0.5,
    0.5,
    -0.5,
    -0.5,
    0.5,
    0.5,
    -0.5,
    0.5, // v0-v1-v2-v3 front
    0.5,
    0.5,
    0.5,
    0.5,
    -0.5,
    0.5,
    0.5,
    -0.5,
    -0.5,
    0.5,
    0.5,
    -0.5, // v0-v3-v4-v5 right
    0.5,
    0.5,
    0.5,
    0.5,
    0.5,
    -0.5,
    -0.5,
    0.5,
    -0.5,
    -0.5,
    0.5,
    0.5, // v0-v5-v6-v1 up
    -0.5,
    0.5,
    0.5,
    -0.5,
    0.5,
    -0.5,
    -0.5,
    -0.5,
    -0.5,
    -0.5,
    -0.5,
    0.5, // v1-v6-v7-v2 left
    -0.5,
    -0.5,
    -0.5,
    0.5,
    -0.5,
    -0.5,
    0.5,
    -0.5,
    0.5,
    -0.5,
    -0.5,
    0.5, // v7-v4-v3-v2 down
    0.5,
    -0.5,
    -0.5,
    -0.5,
    -0.5,
    -0.5,
    -0.5,
    0.5,
    -0.5,
    0.5,
    0.5,
    -0.5, // v4-v7-v6-v5 back
  ];
  return verticesArray;
}

var texcoordArray = [
  // left column front
  0,
  1,
  0,
  0,
  1,
  0,
  1,
  1,

  0,
  1,
  0,
  0,
  1,
  0,
  1,
  1,

  0,
  1,
  0,
  0,
  1,
  0,
  1,
  1,

  0,
  1,
  0,
  0,
  1,
  0,
  1,
  1,

  0,
  1,
  0,
  0,
  1,
  0,
  1,
  1,

  0,
  1,
  0,
  0,
  1,
  0,
  1,
  1,

  0,
  1,
  0,
  0,
  1,
  0,
  1,
  1,

  0,
  1,
  0,
  0,
  1,
  0,
  1,
  1,
  0,
  1,
  0,
  0,
  1,
  0,
  1,
  1,
  0,
  1,
  0,
  0,
  1,
  0,
  1,
  1,
  0,
  1,
  0,
  0,
  1,
  0,
  1,
  1,
  0,
  1,
  0,
  0,
  1,
  0,
  1,
  1,
];

var VSHADER_SOURCE = `

attribute vec4 a_Position;
attribute vec4 a_Color;

attribute vec3 a_Normal;

attribute vec2 a_texcoord;

uniform mat4 u_MvpMatrix;
uniform mat4 u_NormalMatrix;
uniform mat4 u_ModelMatrix;

uniform vec3 u_CameraPosition;

varying vec4 v_Color;
varying vec3 v_Normal;
varying vec3 v_Position;

uniform vec3 u_DianGuangyuanPosition; 
uniform vec3 u_DianGuangyuanColor;

varying vec3 surfaceToLightDirection;
varying vec3 surfaceToViewDirection;

varying vec2 v_texcoord;

void main() {
    v_Normal = mat3(u_NormalMatrix) * a_Normal;

    gl_Position = u_MvpMatrix * a_Position;
    
    v_Position = (u_ModelMatrix * a_Position).xyz;
    v_texcoord = a_texcoord;
    v_Color = a_Color;

    surfaceToLightDirection = u_DianGuangyuanPosition - v_Position;
    surfaceToViewDirection = u_CameraPosition - v_Position;
}
`;

// Fragment shader program
var FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif

varying vec4 v_Color;
varying vec2 v_texcoord;
uniform sampler2D u_texture;

uniform float u_shininess;

varying vec3 v_Normal;
varying vec3 v_Position;

varying vec3 surfaceToLightDirection;
varying vec3 surfaceToViewDirection;

void main() {
    vec3 normal = normalize(v_Normal);

    vec3 halfVector = normalize(normalize(surfaceToLightDirection) + normalize(surfaceToViewDirection));
    
    float light = dot(normal, normalize(surfaceToLightDirection));

    float specular = 0.0;
    if (light > 0.0) {
      specular = pow(dot(normal, halfVector), u_shininess);
    }

    gl_FragColor = texture2D(u_texture, v_texcoord);

    gl_FragColor.rgb *= (light + 0.2);
    gl_FragColor.rgb += specular;
    // gl_FragColor.rgb += 0.2;
}
`;

var VSHADER_SOURCE_C = `
attribute vec4 a_Position;
uniform mat4 u_MvpMatrix;

void main() {
  gl_Position = u_MvpMatrix * a_Position;
}
`;

// Fragment shader program
var FSHADER_SOURCE_C = `
void main() {
  gl_FragColor = vec4(1, 1, 1 ,1); 
}
`;

function radToDeg(r) {
  return (r * 180) / Math.PI;
}

function degToRad(d) {
  return (d * Math.PI) / 180;
}

function createSliders() {
  webglLessonsUI.setupSlider("#dianduanyuan_x", {
    value: dianduanyuan_x,
    slide: updateX,
    min: -30,
    max: 30,
  });

  function updateX(event, ui) {
    dianduanyuan_x = ui.value / 10;
    console.log(dianduanyuan_x);
    draw();
  }

  webglLessonsUI.setupSlider("#dianduanyuan_y", {
    value: dianduanyuan_y,
    slide: updateY,
    min: -30,
    max: 30,
  });

  function updateY(event, ui) {
    dianduanyuan_y = ui.value/ 10;
    draw();
  }

  webglLessonsUI.setupSlider("#dianduanyuan_z", {
    value: dianduanyuan_z,
    slide: updateZ,
    min: -30,
    max: 30,
  });

  function updateZ(event, ui) {
    dianduanyuan_z = ui.value/ 10;
    draw();
  }

  webglLessonsUI.setupSlider("#rotation_pos_x", {
    value: rotation_pos_x,
    slide: update_rotation_pos_x,
    min: -30,
    max: 30,
  });

  function update_rotation_pos_x(event, ui) {
    rotation_pos_x = ui.value;
    draw();
  }

  webglLessonsUI.setupSlider("#rotation_pos_y", {
    value: rotation_pos_y,
    slide: update_rotation_pos_y,
    min: -30,
    max: 30,
  });

  function update_rotation_pos_y(event, ui) {
    rotation_pos_y = ui.value;
    draw();
  }

  webglLessonsUI.setupSlider("#rotation_pos_z", {
    value: rotation_pos_z,
    slide: update_rotation_pos_z,
    min: -30,
    max: 30,
  });

  function update_rotation_pos_z(event, ui) {
    rotation_pos_z = ui.value;
    draw();
  }

  webglLessonsUI.setupSlider("#rotation", {
    value: rotation,
    slide: updateRotation,
    min: -360,
    max: 360,
  });
  function updateRotation(event, ui) {
    rotation = ui.value;
    draw();
  }

  webglLessonsUI.setupSlider("#shinness", {
    value: shinness,
    slide: updateShinness,
    min: 0,
    max: 1000,
  });
  function updateShinness(event, ui) {
    shinness = ui.value;
    draw();
  }
}

var image = new Image();

function main() {
  createSliders();

  image.src = "./icon.png";
  image.addEventListener("load", function () {
    draw();
  });
}

function draw() {
  // Retrieve <canvas> element
  var canvas = document.getElementById("webgl");

  // Get the rendering context for WebGL
  var gl = getWebGLContext(canvas);
  if (!gl) {
    console.log("Failed to get the rendering context for WebGL");
    return;
  }

  // Initialize shaders
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log("Failed to intialize shaders.");
    return;
  }

  var n = initVertexBuffers(gl);
  if (n < 0) {
    console.log("Failed to set the vertex information");
    return;
  }

  var u_ModelMatrix = gl.getUniformLocation(gl.program, "u_ModelMatrix");

  // Get the storage locations of uniform variables and so on
  var u_MvpMatrix = gl.getUniformLocation(gl.program, "u_MvpMatrix");

  var u_DianGuangyuanColor = gl.getUniformLocation(
    gl.program,
    "u_DianGuangyuanColor"
  );
  var u_DianGuangyuanPosition = gl.getUniformLocation(
    gl.program,
    "u_DianGuangyuanPosition"
  );

  var texcoordLocation = gl.getAttribLocation(gl.program, "a_texcoord");
  var textureLocation = gl.getUniformLocation(gl.program, "u_texture");

  var u_NormalMatrix = gl.getUniformLocation(gl.program, "u_NormalMatrix");

  var u_CameraPosition = gl.getUniformLocation(gl.program, "u_CameraPosition");

  var shininessLocation = gl.getUniformLocation(gl.program, "u_shininess");

  // Create a texture.
  var texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);
  // Fill the texture with a 1x1 blue pixel.
  gl.texImage2D(
    gl.TEXTURE_2D,
    0,
    gl.RGBA,
    1,
    1,
    0,
    gl.RGBA,
    gl.UNSIGNED_BYTE,
    new Uint8Array([0, 0, 255, 255])
  );

  // provide texture coordinates for the rectangle.
  var texcoordBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
  // Set Texcoords.
  gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array(texcoordArray),
    gl.STATIC_DRAW
  );
  // Turn on the texcoord attribute
  gl.enableVertexAttribArray(texcoordLocation);

  gl.vertexAttribPointer(texcoordLocation, 2, gl.FLOAT, false, 0, 0);

  gl.uniform1i(textureLocation, 0);

  // 点光源
  // Set the light color (white)
  gl.uniform3f(u_DianGuangyuanColor, 1, 1, 1);
  // Set the light direction (in the world coordinate)
  console.log(dianduanyuan_x, dianduanyuan_y, dianduanyuan_z);
  gl.uniform3f(
    u_DianGuangyuanPosition,
    dianduanyuan_x,
    dianduanyuan_y,
    dianduanyuan_z
  );

  var modelMatrix = new Matrix4();
  // Calculate the model matrix

  modelMatrix.setRotate(
    rotation,
    rotation_pos_x,
    rotation_pos_y,
    rotation_pos_z
  ); // Rotate around the y-axis
  // Pass the model matrix to u_ModelMatrix
  gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);

  // Calculate the view projection matrix
  var mvpMatrix = new Matrix4(); // Model view projection matrix
  mvpMatrix.setPerspective(30, canvas.width / canvas.height, 1, 100);
  var cameraPositionX = 0;
  var cameraPositionY = 0;
  var cameraPositionZ = 10;
  mvpMatrix.lookAt(
    cameraPositionX,
    cameraPositionY,
    cameraPositionZ,
    0,
    0,
    0,
    0,
    1,
    0
  );
  mvpMatrix.multiply(modelMatrix);
  // Pass the model view projection matrix to the variable u_MvpMatrix
  gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);

  var normalMatrix = new Matrix4(); // Transformation matrix for normals

  // Pass the matrix to transform the normal based on the model matrix to u_NormalMatrix
  normalMatrix.setInverseOf(modelMatrix);
  normalMatrix.transpose();
  console.log(modelMatrix);
  gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements);

  var cameraPosition = new Vector3([
    cameraPositionX,
    cameraPositionY,
    cameraPositionZ,
  ]);
  gl.uniform3fv(u_CameraPosition, cameraPosition.elements);
  gl.uniform1f(shininessLocation, shinness);

  // Set the clear color and enable the depth test
  gl.clearColor(0, 0, 0, 1);
  gl.enable(gl.DEPTH_TEST);

  // Clear color and depth buffer
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  // Flip the image's y axis
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
  // Now that the image has loaded make copy it to the texture.
  gl.bindTexture(gl.TEXTURE_2D, texture);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
  gl.generateMipmap(gl.TEXTURE_2D);
  gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);

  /// 灯
  var vertices = new Float32Array(GetVerticesArray());

  // Initialize shaders
  if (!initShaders(gl, VSHADER_SOURCE_C, FSHADER_SOURCE_C)) {
    console.log("Failed to intialize shaders.");
    return;
  }
  if (!initArrayBuffer(gl, "a_Position", vertices, 3)) return -1;

  // Get the storage locations of uniform variables and so on
  var u_MvpMatrix = gl.getUniformLocation(gl.program, "u_MvpMatrix");

  var modelMatrix = new Matrix4();
  console.log(dianduanyuan_x, dianduanyuan_y, dianduanyuan_z);
  // Calculate the model matrix
  modelMatrix = modelMatrix
    .setTranslate(dianduanyuan_x, dianduanyuan_y, dianduanyuan_z)
    .scale(0.2, 0.2, 0.2);

  // Calculate the view projection matrix
  var mvpMatrix = new Matrix4(); // Model view projection matrix
  mvpMatrix.setPerspective(30, canvas.width / canvas.height, 1, 100);
  mvpMatrix.lookAt(
    cameraPositionX,
    cameraPositionY,
    cameraPositionZ,
    0,
    0,
    0,
    0,
    1,
    0
  );
  mvpMatrix.multiply(modelMatrix);
  // Pass the model view projection matrix to the variable u_MvpMatrix
  gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);

  gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
}

function initVertexBuffers(gl) {
  // Create a cube
  //    v6----- v5
  //   /|      /|
  //  v1------v0|
  //  | |     | |
  //  | |v7---|-|v4
  //  |/      |/
  //  v2------v3
  // Coordinates
  var vertices = new Float32Array(GetVerticesArray());

  // Colors
  var colors = new Float32Array(colorsArray);

  // Normal
  var normals = new Float32Array(normalsArray);

  // Indices of the vertices
  var indices = new Uint8Array(indicesArray);

  // Write the vertex property to buffers (coordinates, colors and normals)
  if (!initArrayBuffer(gl, "a_Position", vertices, 3)) return -1;
  if (!initArrayBuffer(gl, "a_Color", colors, 3)) return -1;
  if (!initArrayBuffer(gl, "a_Normal", normals, 3)) return -1;

  // Unbind the buffer object
  gl.bindBuffer(gl.ARRAY_BUFFER, null);

  // Write the indices to the buffer object
  var indexBuffer = gl.createBuffer();
  if (!indexBuffer) {
    console.log("Failed to create the buffer object");
    return false;
  }
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

  return indices.length;
}

function initArrayBuffer(gl, attribute, data, num) {
  // Create a buffer object
  var buffer = gl.createBuffer();
  if (!buffer) {
    console.log("Failed to create the buffer object");
    return false;
  }
  // Write date into the buffer object
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
  // Assign the buffer object to the attribute variable
  var a_attribute = gl.getAttribLocation(gl.program, attribute);
  if (a_attribute < 0) {
    console.log("Failed to get the storage location of " + attribute);
    return false;
  }
  gl.vertexAttribPointer(a_attribute, num, gl.FLOAT, false, 0, 0);
  // Enable the assignment of the buffer object to the attribute variable
  gl.enableVertexAttribArray(a_attribute);

  return true;
}
